package chess

import "fmt"

type Result struct {
	code    uint8
	message string
}

type Piece struct {
	color uint8
}

func (p Piece) GetColor() uint8 {
	return p.color
}

type Point struct {
	index uint8
	upon  *Point
	down  *Point
	left  *Point
	right *Point
	piece *Piece
}

func (point Point) GetPiece() *Piece {
	return point.piece
}

type Chessboard struct {
	board [24]Point
}

func NewChessboard() *Chessboard {
	return &Chessboard{
		board: chessboard(),
	}
}

func (board *Chessboard) PutPiece(location uint8, piece *Piece) Result {
	if location > 23 {
		return Result{201, "Wrong location"}
	}
	point := &board.board[location]
	if point.piece != nil {
		return Result{202, "Point is already in use"}
	}
	point.piece = piece
	return Result{0, nil}
}

func (board *Chessboard) KillPiece(location uint8, color uint8, tag bool) Result {
	if location > 23 {
		return Result{201, fmt.Sprintf("Wrong location %d", location)}
	}
	if color != 1 && color != 2 {
		return Result{204, fmt.Sprintf("Wrong color value %d", color)}
	}
	point := &board.board[location]
	if point.piece == nil {
		return Result{203, "This location has no piece"}
	}
	if point.piece.color != color {
		return Result{205, fmt.Sprintf("Piece color was wrong, color = %d", point.piece.color)}
	}
	if tag {
		point.piece.color = 3
	} else {
		point.piece = nil
	}
	return Result{0, nil}
}

func (board *Chessboard) MovePiece(location uint8, direction uint8, color uint8) Result {
	if location > 23 {
		return Result{201, fmt.Sprintf("Wrong location %d", location)}
	}
	if direction == 0 || direction > 4 {
		return Result{201, fmt.Sprintf("Wrong direction value %d", direction)}
	}
	if color != 1 && color != 2 {
		return Result{204, fmt.Sprintf("Wrong color value %d", color)}
	}
	source := &board.board[location]
	if source.piece.color != color {
		return Result{206, fmt.Sprintf("Wrong piece for move, color = %d", source.piece.color)}
	}
	target := target(source, direction)
	if nil != target {
		piece := source.piece
		source.piece = nil
		target.piece = piece
	}
	return Result{0, nil}
}

func (board *Chessboard) CheckThree(location uint8) uint8 {
	if location > 23 {
		return 0
	}
	point := &board.board[location]
	if point.piece == nil || point.piece.color == 3 { //颜色只有1和2， 3表示吃子标记
		return 0
	}
	return horizontal(point) + vertical(point)
}

func horizontal(point *Point) uint8 {
	var points [3]*Point
	color := point.piece.color
	if point.left == nil {
		points[0] = point
		points[1] = point.right
		points[2] = point.right.right
	} else {
		if point.right == nil {
			points[2] = point
			points[1] = point.left
			points[0] = point.left.left
		} else {
			points[0] = point.left
			points[1] = point
			points[2] = point.right
		}
	}
	return three(points, color)
}

func vertical(point *Point) uint8 {
	var points [3]*Point
	color := point.piece.color
	if point.upon == nil {
		points[0] = point
		points[1] = point.down
		points[2] = point.down.down
	} else {
		if point.down == nil {
			points[2] = point
			points[1] = point.upon
			points[0] = point.upon.upon
		} else {
			points[0] = point.upon
			points[1] = point
			points[2] = point.down
		}
	}
	return three(points, color)
}

func three(points [3]*Point, color uint8) uint8 {
	ret := 0
	for _, point := range points {
		if point.piece.color == color {
			ret = ret + 1
		}
	}
	if ret == 3 {
		return 1
	} else {
		return 0
	}
}

func target(point *Point, direction uint8) *Point {
	switch direction {
	case 1:
		return point.upon
	case 2:
		return point.down
	case 3:
		return point.left
	case 4:
		return point.right
	}
	return nil
}

func (board *Chessboard) points() [24]point {
	var points [24]point
	for _, value := range board.board {
		piece := value.piece
		index := value.index
		if nil == piece {
			points[index] = point{uint32(index), 0}
		} else {
			points[index] = point{uint32(index), uint32(piece.color)}
		}
	}
	return points
}

func chessboard() [24]Point {
	var board [24]Point
	board[0] = Point{0, nil, &board[8], nil, &board[1], nil}
	board[1] = Point{1, nil, nil, &board[0], nil, nil}
	board[2] = Point{2, nil, nil, &board[1], nil, nil}

	return board
}
